function res = features(input, type, varargin)
% FEATURES generate various histograms.
% Usage :
%   RES = FEATURES(INPUT, TYPE[, VARARGIN])
%   This function generates histogram of images specified in INPUT.
%
% Input :
%   INPUT is a matrix of image coef or a path to JPEG images.
%   TYPE is one of the following values:
%     'hist'       : 1D histogram feature of all coeffients.
%                    Output feature is in range [-T:T]. 
%     'point-hist' : 1D histogram feature of single coeffient.
%                    Output feature is in range [-T:T]. 
%     'diff-markov': Directional Difference Markov Feature. 
%                    Output feature is in range [-T:T, -T:T]. 
%     'abs-diff-markov': Directional Difference Markov Feature. 
%                    (use absolute value) 
%                    Output feature is in range [-T:T, -T:T]. 
%     'point-diff-markov' :
%  
%   PARAM is a struct:
%   PARAM.threshold : Threshold value.
%              The default value for 'hist' and 'blockhist' is 10.
%              The default value for 'markov' is 4.
%   PARAM.position  : position of coeffients
%              A 2-by-N matrix.
%
% Output :
%   RES is M*N matrix, where N is the number of features and M is the
%   number of samples.
%

param = [];
nvarargin = length(varargin);
if nvarargin < 1
    switch type
        case 'hist'
            param.threshold = 10;
        case 'point-hist'
            param.threshold = 10;
        case 'point-diff-markov'
            param.threshold = 4;
        case 'diff-markov'
            param.threshold = 4;
        case 'abs-diff-markov'
            param.threshold = 4;
    end
else
    if (~isfloat(varargin{1})) || (varargin{1} <= 0)
        error('Invalid value of threshold.');
    end
    param.threshold = varargin{1};
end

if nvarargin >= 2
    param.position = varargin{2};
end

switch type
    case 'hist'
        N = 2*param.threshold + 1;
    case 'point-hist'
        if ~isfield(param,'position')
            error('Position should be specified.');
        end
        q = size(param.position, 2);
        N = q*(2*param.threshold + 1);
    case 'diff-markov'
        N = 4*(2*param.threshold + 1)^2;
    case 'abs-diff-markov'
        N = 4*(2*param.threshold + 1)^2;
    case 'point-diff-markov'
        if ~isfield(param,'position')
            error('Position should be specified.');
        end
        q = size(param.position, 2);
        N = q*4*(2*param.threshold + 1)^2;
end

if ischar(input)
    inlist = dir([input,'/*.jpg']);
    M = size(inlist, 1);
    res = zeros(M, N);
    count = 0;
    for i = 1:M
        if (inlist(i).isdir ~= 0) || (inlist(i).bytes <= 0)
            continue;
        end
        name = inlist(i).name;
        jobj = jpeg_read([input,'/',name]);
        count = count + 1;
        res(count,:) = hist_proc(jobj.coef_arrays{1}, type, param);

        fprintf(1, 'Processed %s\n', name);
    end
    res = res(1:count,:);
    outfile = sprintf('%s/%s_%d.mat', input, type, param.threshold);
    save(outfile, 'res');
else
    res = hist_proc(input, type, param);
end
end

function h = hist_proc(coef, type, param)
    switch type
        case 'hist'
            h = generateHist(coef, param.threshold);
        case 'blockhist'
            col = size(param.position, 2);
            [M,N] = size(coef);
            h = [];
            for i = 1:col
                single_coef = coef(param.position(1, i):8:M, param.position(2, i):8:N);
                h = [h,generateHist(single_coef, param.threshold)];
            end
        case 'markov'
            h1 = generateHist2D(coef, param.threshold, 'h');
            h2 = generateHist2D(coef, param.threshold, 'v');
            h3 = generateHist2D(coef, param.threshold, 'm');
            h4 = generateHist2D(coef, param.threshold, 'r');
            h = [h1(:);h2(:);h3(:);h4(:)]';
        case 'point-diff-markov'
            h = [];
        case 'diff-markov'
            h = generateDiff2DHist(coef, param.threshold, 0);
        case 'abs-diff-markov'
            h = generateDiff2DHist(coef, param.threshold, 1);
    end
end
